////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek, 1999-2011.
//
// -------------------------------------------------------------------------
//  File name:   FlowMusicPlayPatternNode.h
//  Version:     v1.00
//  Created:     26/05/2011 by Thomas Wollenzin
//  Description: This is the implementation of the FlowMusicPlayPatternNode class
//
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "FlowBaseNode.h"

class CFlowNode_MusicPlayPattern : public CFlowBaseNode<eNCT_Instanced>, IMusicSystemEventListener
{

public:

	//////////////////////////////////////////////////////////////////////////
	CFlowNode_MusicPlayPattern(SActivationInfo* pActInfo)
		: m_fMainPatternCurrentProgress(0.0f),
		  m_fMainPatternPlayTimeInSeconds(0.0f),
		  m_fMainPatternRemainingPlayTimeInSeconds(0.0f),
		  m_bPatternStarted(false),
			m_bPatternFinished(false),
			m_bPatternStopped(false),
			m_psPatternNameTrack1(NULL),
			m_bRegisteredListener(false)
	{
	}

	//////////////////////////////////////////////////////////////////////////
	~CFlowNode_MusicPlayPattern()
	{
			if(m_bRegisteredListener)
				gEnv->pMusicSystem->RemoveEventListener(this);
	}

	//////////////////////////////////////////////////////////////////////////
	IFlowNodePtr Clone(SActivationInfo* pActInfo)
	{
		return new CFlowNode_MusicPlayPattern(pActInfo);
	}

	enum INPUTS 
	{
		eIN_PLAY,
		eIN_STOP,
		eIN_PATTERN,
		eIN_STOP_PREVIOUS,
		eIN_PLAY_SYNCED,
		eIN_PLAY_ON_TOP,
	};

	enum OUTPUTS 
	{
		eOUT_STARTED,
		eOUT_DONE,
		eOUT_FINISHED,
		eOUT_ABORTED,
		eOUT_PROGRESS,
		eOUT_TIME,
		eOUT_TIME_REMAINING
	};

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void GetConfiguration(SFlowNodeConfig& config)
	{
		static const SInputPortConfig inputs[] = 
		{
			InputPortConfig_Void("Play", _HELP("Play the selected music pattern!"), "Play"),
			InputPortConfig_Void("Stop", _HELP("Stop the pattern!"), "Stop"),
			InputPortConfig<string>("patterns_Patterns0", _HELP("Select a music pattern!"), "Pattern"),
			InputPortConfig<bool>("StopPrevious", _HELP("Indicates whether to stop already playing patterns or not."), "StopPrevious"),
			InputPortConfig<bool>("PlaySynced", _HELP("Indicates whether to start at the beginning or at the same time as the currently playing track."), "PlaySynced"),
			InputPortConfig<bool>("PlayOnTop", _HELP("Indicates if this track behaves just like a stinger and plays on top of the current mood without occupying a Track slot."), "PlayOnTop"),
			InputPortConfig_Null()
		};

		static const SOutputPortConfig outputs[] = 
		{
			OutputPortConfig_Void("Started", _HELP("Gets set once the theme and mood started playing."), "Started"),
			OutputPortConfig_Void("Done", _HELP("Gets set when either Finished or Aborted got triggered."), "Done"),
			OutputPortConfig_Void("Finished", _HELP("Gets set when the pattern played until the end."), "Finished"),
			OutputPortConfig_Void("Aborted", _HELP("Gets set when the pattern was stopped prematurely."), "Aborted"),
			OutputPortConfig<float>("Progress", _HELP("Indicates the progress between 0 and 1 of the track currently playing on the main track."), "Progress"),
			OutputPortConfig<float>("Time", _HELP("Indicates the amount of time the current main track pattern has been playing."), "Time"),
			OutputPortConfig<float>("TimeRemaining", _HELP("Indicates the amount of time until the main track pattern ends."), "TimeRemaining"),
			OutputPortConfig_Null()
		};

		config.pInputPorts  = inputs;
		config.pOutputPorts = outputs;
		config.sDescription = _HELP("Play Pattern");
		config.SetCategory(EFLN_APPROVED);
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void Serialize(SActivationInfo* pActivationInfo, TSerialize ser)
	{
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
	{
		switch (event)
		{
		case eFE_Initialize:
			{
			}
			break;
		case eFE_Activate:
			{
				if (IsPortActive(pActInfo, eIN_PLAY))
				{
					bool const bStopPrevious = GetPortBool(pActInfo, eIN_STOP_PREVIOUS);
					bool const bPlaySynced   = GetPortBool(pActInfo, eIN_PLAY_SYNCED);
					bool const bPlayOnTop    = GetPortBool(pActInfo, eIN_PLAY_ON_TOP);
					stack_string const sPattern(GetPortString(pActInfo, eIN_PATTERN));
					gEnv->pMusicSystem->PlayPattern(sPattern.c_str(), bStopPrevious, bPlaySynced, bPlayOnTop);

					pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);

					// Add this instance as listener to the music system
					gEnv->pMusicSystem->AddEventListener(this);
					m_bRegisteredListener = true;
				}
				else if (IsPortActive(pActInfo, eIN_STOP))
				{
					stack_string const sPattern(GetPortString(pActInfo, eIN_PATTERN));
					gEnv->pMusicSystem->StopPattern(sPattern.c_str());
				}
			}
			break;
		case eFE_Update:
			{
				stack_string const sPatternName(GetPortString(pActInfo, eIN_PATTERN));
				bool const bListen = !sPatternName.empty() && m_psPatternNameTrack1 && sPatternName.compareNoCase(m_psPatternNameTrack1) == 0;

				if (bListen)
				{
					ActivateOutput(pActInfo, eOUT_PROGRESS, m_fMainPatternCurrentProgress);
					ActivateOutput(pActInfo, eOUT_TIME, m_fMainPatternPlayTimeInSeconds);
					ActivateOutput(pActInfo, eOUT_TIME_REMAINING, m_fMainPatternRemainingPlayTimeInSeconds);
				}

				if (m_bPatternStarted)
				{
					ActivateOutput(pActInfo, eOUT_STARTED, true);
					m_bPatternStarted = false;
				}

				if (m_bPatternFinished)
				{
					ActivateOutput(pActInfo, eOUT_DONE, true);
					ActivateOutput(pActInfo, eOUT_FINISHED, true);
					m_bPatternFinished = false;
					pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);

					// Remove this instance as listener from the music system
					if(m_bRegisteredListener)
						gEnv->pMusicSystem->RemoveEventListener(this);
				}

				if (m_bPatternStopped)
				{
					ActivateOutput(pActInfo, eOUT_DONE, true);
					ActivateOutput(pActInfo, eOUT_ABORTED, true);
					m_bPatternStopped = false;
					pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);

					// Remove this instance as listener from the music system
					if(m_bRegisteredListener)
						gEnv->pMusicSystem->RemoveEventListener(this);
				}

				break;
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void GetMemoryUsage(ICrySizer * s) const
	{
		s->Add(*this);
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void OnMusicSystemEvent(EMusicSystemCallbackEvent const eEvent, SMusicSystemInfo const& rMusicSystemInfo)
	{
		switch (eEvent)
		{
		case MUSICSYSTEM_EVENT_ON_UPDATE:
			{
				m_fMainPatternCurrentProgress            = rMusicSystemInfo.fMainPatternCurrentProgress;
				m_fMainPatternPlayTimeInSeconds          = rMusicSystemInfo.fMainPatternPlayTimeInSeconds;
				m_fMainPatternRemainingPlayTimeInSeconds = rMusicSystemInfo.fMainPatternRemainingPlayTimeInSeconds;
				m_psPatternNameTrack1                    = rMusicSystemInfo.sMusicPatternNameTrack1.c_str();

				break;
			}
		case MUSICSYSTEM_EVENT_ON_PATTERN_START:
			{
				m_bPatternStarted = true;
					
				break;
			}
		case MUSICSYSTEM_EVENT_ON_PATTERN_FINISHED:
			{
				m_bPatternFinished = true;

				break;
			}
		case MUSICSYSTEM_EVENT_ON_PATTERN_STOP:
			{
				m_bPatternStopped = true;

				break;
			}
		}
	}

private:

	float       m_fMainPatternCurrentProgress;
	float       m_fMainPatternPlayTimeInSeconds;
	float       m_fMainPatternRemainingPlayTimeInSeconds;

	bool        m_bPatternStarted;
	bool        m_bPatternFinished;
	bool        m_bPatternStopped;
	bool				m_bRegisteredListener;

	char const* m_psPatternNameTrack1;
};

REGISTER_FLOW_NODE("Music:PlayPattern", CFlowNode_MusicPlayPattern);
